/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "stdafx.h"
#include "ui文本编辑.h"
#include "系统/系统平台.h"

#include <字符串/str_分割.h>
#include <面/面.h>
#include "core/属性.h"
#include "UI/UI.h"

#include "底层绘图/intern/Vulkan/Vulkan框架.h"


static ivec2 选择开始位置 = {};
static ivec2 选择结束位置 = {};

static vec2 鼠标开始位置 = {};
static vec2 鼠标结束位置 = {};

static bool g文本框选 = false;



void f_ui_编辑框插入文本(C_Widget* self, const std::vector<std::u16string>& 文本块) {
	C_文本编辑框* box = dynamic_cast<C_文本编辑框*>(self);
	if (box) {
		int32 行 = box->m_光标坐标索引.y;
		//if(行) --行;

		for (auto& e : 文本块) {
			auto& lin = box->m_文档->m_文本块[行].m_一行;
			auto& col = box->m_文档->m_文本块[行].m_颜色;

			std::vector<S_RGBA8UI> 新颜色(e.size(), S_UI主题::uic_终端文字);

			lin.insert(lin.end(), e.begin(), e.end());
			col.insert(col.end(), 新颜色.begin(), 新颜色.end());

			box->m_光标坐标索引.x = lin.size();
			box->m_光标坐标索引.y = 行;
			//++行;
			std::cout<<"插入代码\n";
		}
	}
}

static bool on_文本操作菜单项(C_Widget* self, const std::u16string name, uint16 id) {
	switch (id) {
		case 0: {
			break;
		}
		case 1: {
			break;
		}
		case 2: {
			break;
		}
	}
	return false;
}

static bool on_代码提示菜单项(C_Widget* self, const std::u16string name, uint16 id) {
	C_文本编辑框* box = static_cast<C_文本编辑框*>(f_ui_从菜单项取发起组件(self));

	if (box) {
		f_ui_编辑框插入文本(box, {name});
		box->m_更新绘制属性 = true;
	}

	return false;
}





Inline static void f_选区移动到光标位置(C_文本框* box) {
	box->m_选取.开始行列 = { int32(box->m_光标坐标索引.x), int32(box->m_光标坐标索引.y) };
	box->m_选取.结束行列 = box->m_选取.开始行列;
}

static uint8 f_拖拽是否从左开始(C_文本框* editBox) {
	if (editBox->m_选取.结束行列.y == editBox->m_选取.开始行列.y) {
		if (鼠标开始位置.x < 鼠标结束位置.x) {
			return 1;
		}
		else if (鼠标开始位置.x > 鼠标结束位置.x) {
			return 2;
		}
		else {
			return 0;
		}
	}
	else if (editBox->m_选取.结束行列.y > editBox->m_选取.开始行列.y) {
		return 1;
	}
	else if (editBox->m_选取.结束行列.y < editBox->m_选取.开始行列.y) {
		return 2;
	}
	return 0;
}


static void f_行编辑框框选文本(C_文本框* editBox) {
	选择开始位置.x = f_widget_从鼠标取光标索引(editBox, 鼠标开始位置, E_对齐方式::e_左对齐, editBox->m_Text, editBox->m_Size.y);
	选择结束位置.x = f_widget_从鼠标取光标索引(editBox, 鼠标结束位置, E_对齐方式::e_左对齐, editBox->m_Text, editBox->m_Size.y);

	editBox->m_选取.开始行列.x = min(选择开始位置.x, 选择结束位置.x);
	editBox->m_选取.结束行列.x = max(选择结束位置.x, 选择开始位置.x);
	
	editBox->m_光标坐标索引.x = editBox->m_选取.结束行列.x;
	editBox->m_光标坐标索引.y = editBox->m_选取.结束行列.y;
}

static E_事件是否传递 on_编辑框拖拽移动(C_Widget* self, const S_鼠标& 鼠标, S_拖放数据& data) {
	C_行编辑框* box = dynamic_cast<C_行编辑框*>(self);

	if (box->m_开启编辑 && box->m_选择开启) {
		鼠标结束位置 = f_widget_get鼠标局部位置(C_Widget::g_鼠标.gPos, self);

		f_行编辑框框选文本(box);

		if (box->mf_框选时回调) box->mf_框选时回调(self);
		box->m_更新绘制属性 = true;
	}

	return E_事件是否传递::e_事件传递_继续;
}

static E_事件是否传递 on_编辑框开始拖拽(C_Widget* self, const S_鼠标& 鼠标, S_拖放数据& data) {
	C_行编辑框* editBox = dynamic_cast<C_行编辑框*>(self);
	if (editBox->f_使用子类拖放事件()) return E_事件是否传递::e_事件传递_继续;
	else editBox->mf_拖拽 = on_编辑框拖拽移动;

	鼠标开始位置 = f_widget_get鼠标局部位置(C_Widget::g_鼠标.gPos, self);

	editBox->f_置光标索引();
	editBox->m_选取.结束行列 = editBox->m_选取.开始行列;
	editBox->m_选择开启 = true;
	self->m_更新绘制属性 = true;

	g文本框选 = true;
	return E_事件是否传递::e_事件传递_继续;
}

static bool on_编辑框结束拖拽(C_Widget* self, struct C_Widget* 拾取的部件, S_拖放数据& data) {
	C_行编辑框* editBox = dynamic_cast<C_行编辑框*>(self);

	if (editBox->mf_框选后回调) editBox->mf_框选后回调(self);

	if (editBox->m_开启编辑) {
		C_文本框::g选择文本ID区间.x = editBox->m_选取.开始行列.x;
		C_文本框::g选择文本ID区间.y = editBox->m_选取.结束行列.x;

		editBox->mf_拖拽 = on_编辑框拖拽移动;
	}
	
	data.m_Type = E_拖放数据类型::e_鼠标拖放_文本选择;
	//editBox->f_输入完成();
	//editBox->m_选择开启 = false;
	g文本框选 = false;
	return true;
}








bool f_行编辑框_控制键输入(C_文本框* self, const S_键盘& ks) {
	C_行编辑框* box = dynamic_cast<C_行编辑框*>(self);
	//std::cout << "f_KS(ks, S_Input::e_KEY_小键盘数字键_回车) = " << int32(f_KS(ks, S_Input::e_KEY_小键盘数字键_回车)) << std::endl;
	if (f_KS(ks, S_InputKey::e_KEY_退格) == DEF_按键状态_放开) {
		f_行编辑框_退回字符(box);
	} 
	else if (f_KS(ks, S_InputKey::e_KEY_回车) == DEF_按键状态_放开 || f_KS(ks, S_InputKey::e_KEY_小键盘数字键_回车) == DEF_按键状态_放开) {
		self->f_输入完成();
	}
	else if (f_KS(ks, S_InputKey::e_KEY_左CTRL) == DEF_按键状态_按下中 && f_KS(ks, S_InputKey::e_KEY_C) == DEF_按键状态_放开) {
		box->f_拷贝();
	}
	else if (f_KS(ks, S_InputKey::e_KEY_左CTRL) == DEF_按键状态_按下中 && f_KS(ks, S_InputKey::e_KEY_V) == DEF_按键状态_放开) {
		auto text = f_sys_get剪切板文本();
		auto 分割后文本 = f_str_分割(text, u"\r\n");

		f_edit_删除选取文本(box);
		
		box->f_插入文本(分割后文本);
		//std::wcout << "text = " << text << std::endl;
	}
	else if (f_KS(ks, S_InputKey::e_KEY_左CTRL) == DEF_按键状态_按下 || f_KS(ks, S_InputKey::e_KEY_左CTRL) == DEF_按键状态_放开) {
		
		return true;
	}
	else if (f_KS(ks, S_InputKey::e_KEY_左SHIFT) == DEF_按键状态_按下 || f_KS(ks, S_InputKey::e_KEY_左SHIFT) == DEF_按键状态_放开) {

		return true;
	}
	else if (f_KS(ks, S_InputKey::e_KEY_方向_左) == DEF_按键状态_按下) {
		if(box->m_光标坐标索引.x >= 0) --box->m_光标坐标索引.x;
	}
	else if (f_KS(ks, S_InputKey::e_KEY_方向_右) == DEF_按键状态_按下) {
		if(box->m_光标坐标索引.x < int32(box->m_Text.size())) ++box->m_光标坐标索引.x;
	}
	else {
		return false;
	}
	return true;
}



void f_行编辑框_Ascii文本输入(C_行编辑框* box, const S_键盘& ks) {
	uint8 k = f_getKeyUn(ks);
	if (f_KS(ks, k) == DEF_按键状态_放开) {
		uint8 a = f_input_getDXAsciiKey(k);
		if (!a) return;

		if (f_widget_是否处在输入法状态()) {
			ivec2 输入法位置 = { int32(C_文本框::g光标绘制位置.x) , int32(C_文本框::g光标绘制位置.y) };
			输入法位置.y += box->m_行距 + box->m_字号;
			输入法位置.x += box->m_GlobalLoc.x;
			输入法位置.y += box->m_GlobalLoc.y;
			f_widget_set输入法窗口位置(输入法位置);

			//f_widget_set编辑框输入法窗口位置(f_widget_get)
			auto str = f_widget_get输入法文本();
			
			if (str.size()) {
				f_edit_删除选取文本(box);

				if (box->m_光标坐标索引.x > box->m_Text.size()) {
					box->m_Text.insert(box->m_Text.end(), str.begin(), str.end());
				}
				else {
					if (box->m_光标坐标索引.x < box->m_Text.size()) {
						box->m_Text.insert(box->m_Text.begin() + (box->m_光标坐标索引.x + 1), str.begin(), str.end());
					}
					else {
						box->m_Text.insert(box->m_Text.end(), str.begin(), str.end());
					}
				}
				
				
				box->m_光标坐标索引.x += str.size();

				box->m_选取.开始行列.x = box->m_选取.结束行列.x = box->m_光标坐标索引.x;
			}
			
		}
		else {
			if (f_widget_输入法是否有输入()) {
				f_widget_结束输入状态();
			}
			else {
				if (box->mf_文本过滤 && box->mf_文本过滤(box, a)) {
					f_edit_删除选取文本(box);
					/*int32 删除数量 = box->m_选取.结束行列.x - box->m_选取.开始行列.x;
					if (删除数量) {
						box->m_Text.erase(box->m_选取.开始行列.x + 1, 删除数量);
						box->m_光标.x = box->m_选取.开始行列.x;

						box->m_选取.开始行列.x = box->m_选取.结束行列.x = box->m_光标.x;
					}*/


					box->m_光标坐标索引.x = DEF_Min(box->m_光标坐标索引.x, box->m_Text.size());
					box->m_Text.insert(box->m_Text.begin() + box->m_光标坐标索引.x, wchar_t(a));

					++box->m_光标坐标索引.x;
				}
			}
		}

		//box->f_set光标绘制坐标();
	}
}

void f_行编辑框_输入法文本输入(C_行编辑框* box, const S_键盘& ks) {
	if (f_widget_是否处在输入法状态()) {
		if (f_widget_输入法是否有输入()) {
			goto To_正在输入;
		}
	}
	else {
	To_正在输入:
		//auto 中文 = f_widget_get输入法文本();
		f_行编辑框_Ascii文本输入(box, ks);
	}
	
}

void f_行编辑框_退回字符(C_行编辑框* box) {
	if (f_widget_输入法是否有输入()) {
		return;
	}
	int32 删除数量 = box->m_选取.结束行列.x - box->m_选取.开始行列.x;
	if (删除数量) {
		box->m_Text.erase(box->m_选取.开始行列.x + 1, 删除数量);
		box->m_光标坐标索引.x = box->m_选取.开始行列.x;

		box->m_选取.开始行列.x = box->m_选取.结束行列.x = box->m_光标坐标索引.x;
	}
	else {
		if (box->m_Text.size() && box->m_光标坐标索引.x >= 0) {
			auto it = box->m_Text.begin() + DEF_Min(box->m_光标坐标索引.x, box->m_Text.size() - 1);
			box->m_Text.erase(it);
			--box->m_光标坐标索引.x;
		}
	}
}

//bool f_行编辑框_删除选取(C_行编辑框* box) {
//	int32 删除数量 = box->m_选取.结束行列.x - box->m_选取.开始行列.x;
//	if (删除数量) {
//		box->m_Text.erase(box->m_选取.开始行列.x + 1, 删除数量);
//		box->m_光标.x = box->m_选取.开始行列.x;
//		box->m_选取.开始行列.x = box->m_选取.结束行列.x;
//	}
//	return 删除数量;
//}

void f_edit_删除选取文本(C_文本框* 文本框) {
	int32 删除数量 = 文本框->m_选取.结束行列.x - 文本框->m_选取.开始行列.x;

	if (删除数量) {
		文本框->m_Text.erase(文本框->m_选取.开始行列.x, 删除数量);
		文本框->m_光标坐标索引.x = 文本框->m_选取.开始行列.x;
		文本框->m_选取.结束行列.x = 文本框->m_选取.开始行列.x;
	}
}






static bool on_行编辑框_输入字符过滤(C_Widget* self, wchar_t c) {
	if (c >= 2) return true;
	else return false;
}

static E_事件是否传递 on_行编辑框_按键按下(C_Widget* self, const S_键盘& ks) {
	C_行编辑框* editBox = dynamic_cast<C_行编辑框*>(self);

	if (editBox->m_开启编辑) {
		if (f_行编辑框_控制键输入(editBox, ks) == false) {
			f_行编辑框_Ascii文本输入(editBox, ks);

			editBox->m_更新绘制属性 = true;
		}

		if (editBox->mf_文本输入) {
			editBox->mf_文本输入(editBox, editBox->m_Text, E_字符输入类型::e_常规);
		}
	}

	return E_事件是否传递::e_事件传递_终止;
}

static E_事件是否传递 on_编辑框鼠标进入(C_Widget* self, const S_鼠标& 鼠标) {
	//self->m_颜色A = self->m_颜色B + S_RGBA8UI{ 20, 20, 20, 127 };
	self->m_颜色B = {15,15,15,15};
	self->m_父部件->m_更新绘制属性 = true;
	return E_事件是否传递::e_事件传递_继续;
}

static E_事件是否传递 on_编辑框鼠标退出(C_Widget* self, const S_鼠标& 鼠标) {
	//self->m_颜色A = self->m_颜色B;
	self->m_颜色B = {};
	self->m_父部件->m_更新绘制属性 = true;
	return E_事件是否传递::e_事件传递_继续;
}







C_行编辑框::C_行编辑框(S_UI渲染环境& ctx): C_文本框(ctx, S_UI主题::ui_默认字体) {
	m_Type = E_WidgetType::t_行文本编辑框;

	mf_开始拖拽 = on_编辑框开始拖拽;
	mf_结束拖拽 = on_编辑框结束拖拽;
	mf_拖拽		= on_编辑框拖拽移动;

	mf_键盘按键敲击	= on_行编辑框_按键按下;
	mf_文本过滤		= on_行编辑框_输入字符过滤;

	
	mf_鼠标进入 = on_编辑框鼠标进入;
	mf_鼠标离开 = on_编辑框鼠标退出;

	m_图元形状 = &m_UIctx->m_Ctx.m_几何图形->m_平面圆角矩形;
	m_对齐方式 = E_对齐方式::e_左对齐;

	f_set对齐偏移();
	f_setSize({60,20});
	//f_widget_添加绘制画布(this);
}

C_行编辑框::~C_行编辑框() {
	
}

void C_行编辑框::f_绑定事件重置() {
	mf_开始拖拽 = on_编辑框开始拖拽;
	mf_结束拖拽 = on_编辑框结束拖拽;
	mf_拖拽		= on_编辑框拖拽移动;

	mf_键盘按键敲击	= on_行编辑框_按键按下;
	mf_文本过滤		= on_行编辑框_输入字符过滤;
}

bool C_行编辑框::f_使用子类拖放事件() {
	
	return false;
}

void C_行编辑框::f_置光标索引() {
	vec2 鼠标位置 = f_widget_get鼠标局部位置(C_Widget::g_鼠标.gPos, this);
	//float32 行高 = (m_字体->m_字号 + m_字行距);
	f_set对齐偏移();

	m_光标坐标索引.x = f_widget_从鼠标取光标索引(this, 鼠标位置, E_对齐方式::e_左对齐, m_Text, m_Size.y);
}

void C_行编辑框::f_开启输入() {
	
	if (m_开启编辑) {
		if (!g文本框选) {
			m_选取.开始行列 = m_光标坐标索引;
			m_选取.结束行列 = m_选取.开始行列;
		}
	}
	else {
		m_选取.开始行列 = { 0,0 };
		if (m_Text.size()) {
			m_选取.结束行列.x = m_Text.size();
			m_选取.结束行列.y = 0;
		}
		else {
			m_选取.结束行列 = m_选取.开始行列;
		}

		m_渲染层 = DEF_UI_LayerNum - 1;
		m_UIctx->m_GM->f_绑定绘制编辑框(this);
	}
	
	C_文本框::f_开启输入();
}

void C_行编辑框::f_输入完成() {
	C_文本框::f_输入完成();

	switch (m_自定义属性.m_Type) {
	case E_值类型::e_Type_Str:
	case E_值类型::e_Type_LineText:
		f_prop_Str(m_自定义属性) = m_Text;
		break;
	}

	if (m_自定义属性.m_UI && m_自定义属性.m_UI->m_Update) {
		m_自定义属性.m_UI->m_Update(m_自定义属性);
	}
	
	m_UIctx->m_GM->f_解绑编辑框绘制(this);
}

void C_行编辑框::f_拷贝() {
	std::u16string 拷贝文本;

	int32 列开始 = 0;
	int32 列结束 = 0;
	
	列开始 = DEF_Min(m_选取.结束行列.x, m_选取.开始行列.x);
	列结束 = DEF_Max(m_选取.结束行列.x, m_选取.开始行列.x);

	拷贝文本 = m_Text.substr(列开始+1, 列结束 - 列开始);
	m_光标坐标索引.x = 列结束;
	
	
	auto t = f_str_u16_to_u8(拷贝文本);
	f_sys_写到剪切板(t);
}

void C_行编辑框::f_插入文本(const std::vector<std::u16string>& texts) {
	uint32 num = texts.size();
	
	if (num) {
		m_Text.insert(m_光标坐标索引.x + 1, texts[0]);
		m_光标坐标索引.x += texts[0].size();

		f_选区移动到光标位置(this);
	}
}

void C_行编辑框::f_bind属性(S_Props& prop) {
	C_Widget::f_bind属性(prop);

	switch (m_自定义属性.m_Type) {
		case E_值类型::e_Type_Str:
		case E_值类型::e_Type_LineText: {
			m_Text = f_prop_Str(m_自定义属性);
			break;
		}
		default:
			break;
	}
}

void C_行编辑框::f_set对齐偏移() {
	//const auto& 字体 = f_surface_get字体库(*m_UIctx, S_UI主题::ui_默认字体);

	//if (m_对齐方式 == E_对齐方式::e_据中对齐) {
	//	m_文本对齐偏移 = f_widget_get文字绘制据中偏移(m_Size, m_Text, 字体, S_UI主题::ui_文字间隔);
	//}
	//else if (m_对齐方式 == E_对齐方式::e_左对齐) {
	//	m_文本对齐偏移 = f_widget_get文字左对齐偏移位置(m_Size, m_Text, 字体, S_UI主题::ui_文字间隔);
	//	m_文本对齐偏移.x += m_文字边间距.x;
	//}
	
	C_文本框::g光标绘制位置.y = 0;
}

C_Widget* f_ui_创建行文本编辑框(S_UI渲染环境& ctx) {
	C_行编辑框* box = new C_行编辑框(ctx);
	box->f_setSize({200,24});
	return box;
}

void f_ui_bind编辑框完成回调(C_Widget* self, fp_Widget文本输入完成 f输入完成) {
	dynamic_cast<C_文本框*>(self)->mf_文本完成 = f输入完成;
}

void f_ui_set行编辑框文本(C_Widget* self, std::u16string text) {
	C_文本框* box = dynamic_cast<C_文本框*>(self);
	box->m_Text = text;
	box->m_更新绘制属性 = true;
}

void f_ui_set编辑框绘制标题(C_Widget* self, bool o) {
	//C_行编辑框* box = dynamic_cast<C_行编辑框>(self);

}

void f_ui_行编辑框绑定属性(C_Widget* self, S_Props& prop) {
	dynamic_cast<C_行编辑框*>(self)->m_自定义属性 = prop;
}






static bool on_文本编辑框_输入字符过滤(C_Widget* self, wchar_t ASCII) {
	auto* editBox = dynamic_cast<C_文本框*>(self);
	//std::cout << "A  input.m_Key.Keys[k] == " << int32(ASCII) << " _ " << std::endl;
	if (ASCII >= 32 && ASCII < 126) {
		uint32 num = editBox->m_Text.size();
		//std::cout << "input.m_Key.Keys[k] == " << int32(ASCII) << " _ " << std::endl;
		return true;
	}

	return false;
}


bool f_文本编辑框_控制键输入(C_文本框* self, const S_键盘& ks, const int8 c) {
	C_文本编辑框* editBox = dynamic_cast<C_文本编辑框*>(self);
	wchar_t 中 = 0;

	bool 是否有输入 = false;
	//std::cout << "f_KS(ks, S_Input::e_KEY_小键盘数字键_回车) = " << int32('c') << " " << c << std::endl;
	uint32 按下中 = DEF_按键状态_按下 | DEF_按键状态_按下中;

	if (f_KS(C_Widget::g_键盘, S_InputKey::e_KEY_左CTRL) == DEF_按键状态_按下中 && c == 'C') {
		editBox->f_拷贝();
		是否有输入 = true;
	}
	else if (f_KS(C_Widget::g_键盘, S_InputKey::e_KEY_左CTRL) == DEF_按键状态_按下中 && c == 'V') {
		auto text = f_sys_get剪切板文本();
		std::vector<std::u16string> 分隔符 = { u"\r\n", u"\r", u"\n" };

		auto 分割后文本 = f_str_分割(text, 分隔符);
		editBox->f_插入文本(分割后文本);
		是否有输入 = true;
	}
	else if (f_KS(ks, S_InputKey::e_KEY_左CTRL) == DEF_按键状态_按下中 && c == 'X') {
		editBox->f_剪切();
		self->m_父部件->m_更新绘制属性 = true;
		是否有输入 = true;
	}
	else if (f_KS(ks, S_InputKey::e_KEY_左CTRL) == DEF_按键状态_按下中 && f_KS(ks, S_InputKey::e_KEY_左SHIFT) == DEF_按键状态_按下中) {
		self->m_父部件->m_更新绘制属性 = true;
		是否有输入 = true;
	}
	else if (f_KS(C_Widget::g_键盘, S_InputKey::e_KEY_方向_左) & 按下中 || c == VK_LEFT) {
		--editBox->m_光标坐标索引.x;
		if (editBox->m_光标坐标索引.x < 0) {
			goto To_光标上移;
		}
		f_选区移动到光标位置(editBox);
		是否有输入 = true;
	}
	else if (f_KS(C_Widget::g_键盘, S_InputKey::e_KEY_方向_右) & 按下中 || c == VK_RIGHT) {
		if (editBox->m_光标坐标索引.x <= editBox->m_文档->m_文本块[editBox->m_光标坐标索引.y].m_一行.size()) {
			++editBox->m_光标坐标索引.x;
		}
		else {
			if (editBox->m_光标坐标索引.y + 1 < editBox->m_文档->m_文本块.size()) {
				editBox->m_光标坐标索引.x = 0;
				goto To_光标下移;
			}
		}
		f_选区移动到光标位置(editBox);
		是否有输入 = true;
	}
	else if (f_KS(C_Widget::g_键盘, S_InputKey::e_KEY_方向_上) & 按下中 || c == VK_UP) {
	To_光标上移:
		if (editBox->m_光标坐标索引.y) {
			--editBox->m_光标坐标索引.y;
			if (uint32(editBox->m_光标坐标索引.x) > editBox->m_文档->m_文本块[editBox->m_光标坐标索引.y].m_一行.size()) {
				editBox->m_光标坐标索引.x = editBox->m_文档->m_文本块[editBox->m_光标坐标索引.y].m_一行.size();
			}
		}
		f_选区移动到光标位置(editBox);
		是否有输入 = true;
	}
	else if (f_KS(C_Widget::g_键盘, S_InputKey::e_KEY_方向_下) & 按下中 || c == VK_DOWN) {
	To_光标下移:
		if (editBox->m_光标坐标索引.y + 1 < editBox->m_文档->m_文本块.size()) {
			++editBox->m_光标坐标索引.y;

			if (editBox->m_光标坐标索引.x > editBox->m_文档->m_文本块[editBox->m_光标坐标索引.y].m_一行.size()) {
				editBox->m_光标坐标索引.x = editBox->m_文档->m_文本块[editBox->m_光标坐标索引.y].m_一行.size();
			}
		}
		f_选区移动到光标位置(editBox);
		是否有输入 = true;
	}
	else if (c == '\t') {
		editBox->f_插入字符('\t', editBox->m_光标坐标索引);
		++(editBox->m_光标坐标索引.x);

		editBox->m_选取.开始行列 = { int32(editBox->m_光标坐标索引.x) , int32(editBox->m_光标坐标索引.y) };
		editBox->m_选取.结束行列 = editBox->m_选取.开始行列;
		是否有输入 = true;
	}
	else if (f_KS(ks, S_InputKey::e_KEY_退格) == DEF_按键状态_放开) {
		
	}
	else if (c == '\b') {
		//std::cout<<"退格输入\n";
		if (editBox->m_选取.开始行列 == editBox->m_选取.结束行列) {
			auto& e = editBox->m_文档->m_文本块[editBox->m_光标坐标索引.y];
			--editBox->m_光标坐标索引.x;
			if (editBox->m_光标坐标索引.x == 0) {
				e.m_一行.clear();
				e.m_颜色.clear();
			}
			else if (editBox->m_光标坐标索引.x < 0) {
				if(editBox->m_光标坐标索引.y > 0) {
					if (e.m_一行.empty()) {
						editBox->m_文档->m_文本块.erase(editBox->m_文档->m_文本块.begin() + editBox->m_光标坐标索引.y);
						goto To_光标上移;
					}
					else {
						
						auto& 上一行 = editBox->m_文档->m_文本块[editBox->m_光标坐标索引.y - 1];
						editBox->m_光标坐标索引.x = 上一行.m_一行.size();

						上一行.m_一行.insert(上一行.m_一行.end(), e.m_一行.begin(), e.m_一行.end());
						上一行.m_颜色.insert(上一行.m_颜色.end(), e.m_颜色.begin(), e.m_颜色.end());

						editBox->m_文档->m_文本块.erase(editBox->m_文档->m_文本块.begin() + editBox->m_光标坐标索引.y);
						--editBox->m_光标坐标索引.y;

						assert(editBox->m_光标坐标索引.y < editBox->m_文档->m_文本块.size());
					}
				}
				else {
					e.m_一行.clear();
					e.m_颜色.clear();
					editBox->m_光标坐标索引.x = 0;
				}
			}
			else if (editBox->m_光标坐标索引.x >= e.m_一行.size()) {
				e.m_一行.pop_back();
				e.m_颜色.pop_back();
				editBox->m_光标坐标索引.x = e.m_一行.size();
			}
			else {
				e.m_一行.erase(editBox->m_光标坐标索引.x, 1);
				e.m_颜色.erase(e.m_颜色.begin() + editBox->m_光标坐标索引.x);
			}

		}
		else {
			editBox->f_删除选择字符();
		}

		是否有输入 = true;
	}
	else if (c == '\r') {
   		if (f_ui_执行菜单项事件(editBox->mui_代码提示菜单) < 0) {
			editBox->f_插入行(editBox->m_光标坐标索引.y);
		}

		editBox->m_选取.开始行列 = { int32(editBox->m_光标坐标索引.x) , int32(editBox->m_光标坐标索引.y) };
		editBox->m_选取.结束行列 = editBox->m_选取.开始行列;
		//std::cout<<"**代码换行**\n";
		是否有输入 = true;
	}
	else {
		是否有输入 = false;
	}

	if (是否有输入) {
		self->m_父部件->m_更新绘制属性 = true;
	}
	
	return 是否有输入;
}


static E_事件是否传递 on_文本编辑框_按键按下(C_Widget* self, const S_键盘& ks) {
	C_文本框* editBox = dynamic_cast<C_文本框*>(self);
	wchar_t ASCII = 0;
	bool 是否有输入 = false;

	//f_文本编辑框_控制键输入(editBox, ks, 0);
	return E_事件是否传递::e_事件传递_终止;
}

static bool on_文本编辑框_字符输入(C_Widget* self, const int8 c, uint8 flag) {
	C_文本编辑框& box = *dynamic_cast<C_文本编辑框*>(self);
	wchar_t ASCII = c;
	
	bool 是否有组合输入 = false;
	float32 dpi = self->m_UIctx->m_DPI;

	if (flag) {
		是否有组合输入 = f_文本编辑框_控制键输入(&box, C_Widget::g_键盘, c);
	}
	else {
		box.f_插入字符(ASCII, box.m_光标坐标索引);
		++(box.m_光标坐标索引.x);
		是否有组合输入 = true;

		if (box.mf_字符输入回调) {
			box.mf_字符输入回调(self, c);
		}
	}

	if (是否有组合输入) {
		box.m_选取.开始行列 = { int32(box.m_光标坐标索引.x) , int32(box.m_光标坐标索引.y) };
		box.m_选取.结束行列 = box.m_选取.开始行列;
	}

	
	
	self->m_父部件->m_更新绘制属性 = true;
	return 是否有组合输入;
}

static void on_文本编辑框_输入法输入(C_Widget* self, const std::u16string& text, E_字符输入类型 输入类型) {
	C_文本编辑框& box = *dynamic_cast<C_文本编辑框*>(self);

	if (text.size()) {
		float32 dpi = self->m_UIctx->m_DPI;

		switch (输入类型) {
			case E_字符输入类型::e_常规:
				break;
			
			case E_字符输入类型::e_输入法字符:
				box.f_插入字符(text.back(), box.m_光标坐标索引);
				++(box.m_光标坐标索引.x);
				box.m_选取.结束行列.x = box.m_光标坐标索引.x;
				break;
			case E_字符输入类型::e_输入法组合:
				box.f_插入文本({text});
				break;
			case E_字符输入类型::e_末尾行插入: {
				
				break;
			}
			default:
				break;
		}
		

		vec2 光标绘制位置 = box.f_光标绘制坐标();

		float32 行高 = (box.m_字号 + box.m_行距) * dpi;
		ivec2 输入法位置 = { int32(光标绘制位置.x) , int32(光标绘制位置.y) };
		//输入法位置.y += 行高;

		输入法位置.x += self->m_GlobalLoc.x;
		输入法位置.y += self->m_GlobalLoc.y;

 		f_widget_set输入法窗口位置(输入法位置);


		if (box.mf_字符输入回调) {
			box.mf_字符输入回调(self, text.back());
		}
	}

	self->m_父部件->m_更新绘制属性 = true;
}


static E_事件是否传递 on_文本编辑框开始拖拽(C_Widget* self, const S_鼠标& 鼠标, S_拖放数据& data) {
	C_文本编辑框* editBox = dynamic_cast<C_文本编辑框*>(self);
	//if (editBox->f_使用子类拖放事件()) return true;
	editBox->f_置光标索引();

	editBox->m_选择开启 = true;
	self->m_更新绘制属性 = true;

	return E_事件是否传递::e_事件传递_继续;
}

static E_事件是否传递 on_文本编辑框拖拽(C_Widget* self, const S_鼠标& 鼠标, S_拖放数据& data) {
	C_文本编辑框* editBox = dynamic_cast<C_文本编辑框*>(self);
	//if (!editBox->m_开启编辑) return true;
	if (editBox->m_选择开启) {
		editBox->m_光标坐标索引 = editBox->f_计算光标索引();
		editBox->m_选取.结束行列 = editBox->m_光标坐标索引;

		if (editBox->mf_框选时回调) editBox->mf_框选时回调(self);
		self->m_更新绘制属性 = true;
	}

	return E_事件是否传递::e_事件传递_终止;
}

static bool on_文本编辑框结束拖拽(C_Widget* self, C_Widget* 拾取的部件, S_拖放数据& data) {
	C_文本编辑框* editBox = dynamic_cast<C_文本编辑框*>(self);

	if (editBox->mf_文本完成) editBox->mf_文本完成(self);
	if (editBox->m_开启编辑) {
		
	}

	return E_事件是否传递::e_事件传递_终止;
}

static E_事件是否传递 on_文本编辑框鼠标进入(C_Widget* self, const S_鼠标& 轮值) {
	C_文本编辑框& 手柄 = *static_cast<C_文本编辑框*>(self);
	if (self->f_get窗口管理()->m_当前文本输入框 == nullptr) {
		手柄.f_开启输入();
	}

	return E_事件是否传递::e_事件传递_继续;
}

static E_事件是否传递 on_文本编辑框鼠标移出(C_Widget* self, const S_鼠标& 轮值) {
	C_文本编辑框& 手柄 = *static_cast<C_文本编辑框*>(self);

	return E_事件是否传递::e_事件传递_继续;
}


static E_事件是否传递 on_编辑框鼠标按键按下(C_Widget* self, const E_鼠标按钮& 按钮) {
	//vec2 鼠标位置  = ;
	switch (按钮) {
		case E_鼠标按钮::e_鼠标右键: {
			if (self->m_Type == E_WidgetType::t_文本编辑框) {
				C_文本编辑框* editBox = dynamic_cast<C_文本编辑框*>(self);
				f_ui_打开弹出窗口(editBox->mui_文本操作菜单, C_Widget::g_鼠标.gPos);
			}
			
			break;
		}
	}
	return E_事件是否传递::e_事件传递_终止;
}

static E_事件是否传递 on_编辑框_鼠标双击(C_Widget* self, const E_鼠标按钮& 按钮) {
	//std::cout << "双击" << std::endl;
	C_文本编辑框* editBox = dynamic_cast<C_文本编辑框*>(self);

	auto& str = editBox->m_文档->m_文本块[editBox->m_光标坐标索引.y].m_一行;
	int32 num = str.size();

	int32 begin = editBox->m_光标坐标索引.x + 1;
	int32 end = editBox->m_光标坐标索引.x;
	for (int32 i = editBox->m_光标坐标索引.x; i >= 0; --i) {
		switch (str[i]) {
		case '.':
		case '-':
		case '+':
		case '*':
		case '/':
		case '[':
		case ']':
		case '{':
		case '}':
		case '(':
		case ')':
		case '"':
		case ';':
		case ':':
		case ' ':
		case '<':
		case '>':
		case ',':
		case '=':
		case '\t':
			goto To_后段计算;
			break;
		default:
			--begin;
			break;
		}
	}

	To_后段计算:
	for (int32 i = editBox->m_光标坐标索引.x; i < num; ++i) {
		switch (str[i]) {
		case '.':
		case '-':
		case '+':
		case '*':
		case '/':
		case '[':
		case ']':
		case '{':
		case '}':
		case '(':
		case ')':
		case '"':
		case ';':
		case ':':
		case ' ':
		case '<':
		case '>':
		case ',':
		case '=':
		case '\t':
			goto To_end;
			break;
		default:
			++end;
			break;
		}
	}

To_end:
	if (begin < 0) begin = 0;

	editBox->m_选取.开始行列.x = begin;
	editBox->m_选取.开始行列.y = editBox->m_光标坐标索引.y;
	editBox->m_选取.结束行列.x = end;
	editBox->m_选取.结束行列.y = editBox->m_光标坐标索引.y;

	editBox->m_光标坐标索引.x = end;

	if (editBox->mf_框选时回调) editBox->mf_框选时回调(self);
	return E_事件是否传递::e_事件传递_终止;
}

static E_事件是否传递 on_编辑框_鼠标点击(C_Widget* self, const E_鼠标按钮& 按钮) {
	C_文本编辑框& box = *dynamic_cast<C_文本编辑框*>(self);

	auto gm = self->f_get窗口管理();
	if (gm->m_当前独占操作文本框 && gm->m_当前独占操作文本框 != &box) {
		gm->m_当前独占操作文本框->f_输入完成();
	}

	if (gm->m_当前文本输入框 && gm->m_当前文本输入框 != &box && dynamic_cast<C_文本框*>(gm->m_当前文本输入框)) {
		dynamic_cast<C_文本框*>(gm->m_当前文本输入框)->f_输入完成();
	}

	if (box.m_开启编辑 == false) {
		box.f_开启输入();
	}
	box.f_置光标索引();
	box.f_光标绘制坐标();



	self->m_更新绘制属性 = true;
	return E_事件是否传递::e_事件传递_终止;
}

static void on_文本编辑框绘制(C_Widget* self, S_2D画布* 画布) {
	C_文本编辑框& box = *(C_文本编辑框*)(self);

	box.m_背景 = f_vg_genConvex((*self), *画布, E_填充模式::e_填充面, E_图层混合模式::e_Normal);
	box.m_线条 = f_vg_genConvex((*self), *画布, E_填充模式::e_填充线, E_图层混合模式::e_Normal);
	box.m_字符 = f_vg_genString((*self), *画布, E_填充模式::e_填充面, E_图层混合模式::e_Normal, u"雅黑");
	box.m_光标 = f_vg_genConvex((*self), *画布, E_填充模式::e_填充面, E_图层混合模式::e_Normal);

	//box.m_光标 = f_vg_genLine((*self), *画布, E_图层混合模式::e_Normal, E_线类型::e_线段);
	box.m_线条->m_线宽 = 1.5;
}

static void on_文本编辑框变换(C_Widget* self) {
	C_文本编辑框& box = *(C_文本编辑框*)(self);
	auto* rf = f_vk_get绘图框架((*self));
	float dpi = self->m_UIctx->m_DPI;


	std::vector<std::u16string>			字符字符;
	std::vector<S_Rect2Df>				字符区域;
	std::vector<E_对齐方式>				字符对齐;
	std::vector<std::vector<S_RGBA8UI>>	字符颜色;

	float32 行高 = (box.m_字号 + box.m_行距) * dpi;
	S_Rect2Df rect{};
	
	rect.extent = {self->m_Size.x, 行高};

	int32 行开始偏移 = 0;
	int32 有效行显示数量 = f_ui_Layout_行显示范围(self, 行高, box.m_文档->m_文本块.size(), 行开始偏移);
	rect.offset.y = 行开始偏移*行高;

	for (int32 i = 0; i < 有效行显示数量; ++i) {
		auto& e = box.m_文档->m_文本块[行开始偏移 + i];

		字符字符.emplace_back(e.m_一行);
		字符颜色.push_back(e.m_颜色);
		字符区域.push_back(rect);
		字符对齐.emplace_back(E_对齐方式::e_左对齐);

		rect.offset.y += 行高;
	}
	

	S_字符串绘制属性 字符串绘制属性;
	字符串绘制属性.m_字号 = box.m_字号 * dpi;
	字符串绘制属性.m_间距 = box.m_字间距 * dpi;
	字符串绘制属性.m_行距 = box.m_行距 * dpi;
	字符串绘制属性.m_方向 = E_方向::e_横向;
	f_vg_drawStringBlock(*box.m_字符, 字符字符, 字符区域, 字符颜色, 字符对齐, 字符串绘制属性);


	vec2 光标坐标 = box.f_光标绘制坐标();
	ivec2 开始行列;
	ivec2 结束行列;
	uint32 选择行数量 = box.f_构建正向选择区间(开始行列, 结束行列);


	std::vector<S_2DConvexRect>	区域;
	std::vector<S_GPU内存块*>	形状;
	std::vector<vec2>			位置;
	std::vector<S_2D颜色包>		颜色;
	uint32 预分配数量 = box.m_代码包裹.size() + 选择行数量 + 1;
	区域.reserve(预分配数量);
	形状.reserve(预分配数量);
	位置.reserve(预分配数量);
	颜色.reserve(预分配数量);


	S_2DConvexRect 形状区域{};
	形状区域.AA_type = { 1, 0 };
	形状区域.radius = _Vec2(6 * dpi);
	for (auto& e : box.m_代码包裹) {
		形状区域.size = { float32(e.z), e.y * 行高};

		区域.push_back(形状区域);
		形状.push_back(&self->m_UIctx->m_Ctx.m_几何图形->m_平面圆角矩形);
		位置.push_back({ 0, e.x * 行高 });
		颜色.push_back(S_2D颜色包(S_UI主题::uic_编辑框包裹背景));
	}
	f_vg_drawConvex(*box.m_线条, 形状.size(), 形状.data(), 区域.data());
	f_vg_tranform(*box.m_线条, 位置.size(), 位置.data());
	f_vg_color(*box.m_线条, 颜色.size(), 颜色.data());



	形状区域 = {};
	形状区域.AA_type	= { 1, 0 };
	
	if (box.m_选取.结束行列 == box.m_选取.开始行列) {
		
	}
	else {
		
		auto str_s_A = box.m_文档->m_文本块[开始行列.y].m_一行.substr(0, 开始行列.x);
		float32 strWidth = f_vg_getStringSize(*(box.m_字符->m_字体), str_s_A, box.m_字号 * dpi, 字符串绘制属性.m_间距);
		strWidth += f_vg_StringDrawOffset(行高);

		if (选择行数量 < 1) {
			auto str_s_B = box.m_文档->m_文本块[开始行列.y].m_一行.substr(开始行列.x, 结束行列.x - 开始行列.x);
			形状区域.size.x = f_vg_getStringSize(*(box.m_字符->m_字体), str_s_B, box.m_字号 * dpi, 字符串绘制属性.m_间距);
		}
		else {
			auto str_s_B = box.m_文档->m_文本块[开始行列.y].m_一行.substr(开始行列.x, -1);
			形状区域.size.x = f_vg_getStringSize(*(box.m_字符->m_字体), str_s_B, box.m_字号 * dpi, 字符串绘制属性.m_间距);
		}
		形状区域.size.x += 字符串绘制属性.m_间距;

		形状区域.size.y = 行高;

		区域.emplace_back(形状区域);
		形状.emplace_back(&self->m_UIctx->m_Ctx.m_几何图形->m_平面矩形);
		位置.push_back({ strWidth, 行高 * 开始行列.y });
		颜色.push_back(S_2D颜色包(S_UI主题::uic_值编辑框文字焦点背景));

		for (uint32 i = 1; i < 选择行数量; ++i) {
			uint32 index = 开始行列.y + i;

			auto str_s = box.m_文档->m_文本块[index].m_一行;
			形状区域.size.x = f_vg_getStringSize(*(box.m_字符->m_字体), str_s, box.m_字号 * dpi, 字符串绘制属性.m_间距);
			形状区域.size.x += 字符串绘制属性.m_间距;
			区域.emplace_back(形状区域);
			形状.emplace_back(&self->m_UIctx->m_Ctx.m_几何图形->m_平面矩形);
			位置.push_back({f_vg_StringDrawOffset(行高), 行高 * index });
			颜色.push_back(S_2D颜色包(S_UI主题::uic_值编辑框文字焦点背景));
		}

		if (选择行数量 >= 1) {
			auto str_s_B = box.m_文档->m_文本块[结束行列.y].m_一行.substr(0, 结束行列.x);
			形状区域.size.x = f_vg_getStringSize(*(box.m_字符->m_字体), str_s_B, box.m_字号 * dpi, 字符串绘制属性.m_间距);
			形状区域.size.x += 字符串绘制属性.m_间距;
			区域.emplace_back(形状区域);
			形状.emplace_back(&self->m_UIctx->m_Ctx.m_几何图形->m_平面矩形);
			位置.push_back({f_vg_StringDrawOffset(行高), 行高 * 结束行列.y });
			颜色.push_back(S_2D颜色包(S_UI主题::uic_值编辑框文字焦点背景));
		}
	}
	f_vg_drawConvex(*box.m_背景, 形状.size(), 形状.data(), 区域.data());
	f_vg_tranform(*box.m_背景, 位置.size(), 位置.data());
	f_vg_color(*box.m_背景, 颜色.size(), 颜色.data());


	形状区域.size = { 2, 行高 };

	区域 = {形状区域};
	位置 = {光标坐标};
	形状 = {&self->m_UIctx->m_Ctx.m_几何图形->m_平面矩形};
	颜色 = {S_2D颜色包(S_UI主题::uic_行编辑框光标)};

	//f_vg_setLine()
	f_vg_drawConvex(*box.m_光标, 形状.size(), 形状.data(), 区域.data());
	f_vg_tranform(*box.m_光标, 位置.size(), 位置.data());
	f_vg_color(*box.m_光标, 颜色.size(), 颜色.data());
}


C_文本编辑框::C_文本编辑框(S_UI渲染环境& ctx, std::u16string 字体名称) : C_文本框(ctx, 字体名称) {
	m_WName = u"文本编辑框";
	m_TypeName = "C_文本编辑框";

	m_Type = E_WidgetType::t_文本编辑框;

	f_widget_添加绘制画布(this);
	mf_绘制 = on_文本编辑框绘制;
	mf_变换 = on_文本编辑框变换;

	m_字号 = 24;
	m_对齐方式 = E_对齐方式::e_左对齐;

	mf_文本过滤 = on_文本编辑框_输入字符过滤;

	
	mf_鼠标按键按下	= on_编辑框鼠标按键按下;
	mf_鼠标按键双击	= on_编辑框_鼠标双击;
	mf_鼠标点击		= on_编辑框_鼠标点击;

	mf_行文本输入	= on_文本编辑框_输入法输入;
	mf_键盘按键敲击	= on_文本编辑框_按键按下;
	mf_按键字符输入	= on_文本编辑框_字符输入;
	


	mf_开始拖拽 = on_文本编辑框开始拖拽;
	mf_结束拖拽 = on_文本编辑框结束拖拽;
	mf_拖拽		= on_文本编辑框拖拽;


	mf_鼠标进入 = on_文本编辑框鼠标进入;
	mf_鼠标离开 = on_文本编辑框鼠标移出;
	

	
	mf_框选时回调 = nullptr;
	mf_框选后回调 = nullptr;

	m_文本对齐偏移.x = 50 * ctx.m_DPI;

	m_文档->m_文本块.push_back({});
	//m_文档->m_文本块.front().m_一行 = u"MBT测试";
	//m_文档->m_文本块.front().m_颜色 = {S_UI主题::uic_文字颜色, S_UI主题::uic_文字颜色, S_UI主题::uic_文字颜色, S_UI主题::uic_文字颜色, S_UI主题::uic_文字颜色};
	mui_代码提示菜单 = f_ui_创建菜单(ctx, E_方向::e_纵向);
	mui_代码提示菜单->m_ColorA = S_2D颜色包({128,128,128,128}, 255, 30, 0);
	mui_代码提示菜单->m_间隔宽度 = 0;
	mui_代码提示菜单->m_强制焦点 = true;
	f_ui_菜单关闭方式(mui_代码提示菜单, E_菜单关闭方式::e_ESC取消);

	mui_文本操作菜单 = f_ui_创建菜单(ctx, E_方向::e_纵向);
	mui_文本操作菜单->m_ColorA = S_2D颜色包({128,128,128,128}, 255, 30, 0);

	

	S_菜单创建参数 文本操作菜单参数 = {
		on_文本操作菜单项, {

			{u"复制", u"",  u"Ctrl+C", 0},
			{u"粘贴", u"",  u"Ctrl+V", 0},
			{u"剪切", u"",  u"Ctrl+X", 0},
			//{u"另存", u"doc_plus",  u"",0},
		}
	};
	f_ui_添加菜单项(mui_文本操作菜单, 文本操作菜单参数, 1, 50);

}

C_文本编辑框::~C_文本编辑框() {
	f_ui_销毁菜单(mui_代码提示菜单);
	f_ui_销毁菜单(mui_文本操作菜单);
}

void C_文本编辑框::f_插入字符(wchar_t t, ivec2 pos) {
	if (m_文档->m_文本块.size() > pos.y) {
		if (m_文档->m_文本块[pos.y].m_一行.size() > pos.x) {
			m_文档->m_文本块[pos.y].m_一行.insert(m_文档->m_文本块[pos.y].m_一行.begin() + pos.x, t);
			m_文档->m_文本块[pos.y].m_颜色.insert(m_文档->m_文本块[pos.y].m_颜色.begin() + pos.x, S_UI主题::uic_终端文字);
		}
		else {
			m_文档->m_文本块[pos.y].m_一行.push_back(t);
			m_文档->m_文本块[pos.y].m_颜色.push_back(S_UI主题::uic_终端文字);
		}
	}
}

void C_文本编辑框::f_删除字符(ivec2 pos) {
	if (m_文档->m_文本块.size() > pos.y) {
		if (m_文档->m_文本块[pos.y].m_一行.size() > pos.x) {
			m_文档->m_文本块[pos.y].m_一行.erase(pos.x, 1);
			m_文档->m_文本块[pos.y].m_颜色.erase(m_文档->m_文本块[pos.y].m_颜色.begin() + pos.x);
		}
		else {
			m_文档->m_文本块[pos.y].m_一行.pop_back();
			m_文档->m_文本块[pos.y].m_颜色.pop_back();
		}
	}
}

void C_文本编辑框::f_插入行(uint32 行号) {
	E_字符输入类型 输入类型;

	if (m_文档->m_文本块.size() <= 行号) {
		输入类型 = E_字符输入类型::e_末尾行插入;
		S_着色文本块 文本块{};
		m_文档->m_文本块.push_back(文本块);
	}
	else {
		if (f_拆分行(m_光标坐标索引)) {
			输入类型 = E_字符输入类型::e_拆分行;
		}
		else {
			S_着色文本块 文本块{};
			m_文档->m_文本块.insert(m_文档->m_文本块.begin() + 行号 + 1, 文本块);

			输入类型 = E_字符输入类型::e_末尾行插入;
		}
	}

	m_光标坐标索引.x = 0;
	m_光标坐标索引.y = 行号 + 1;

	if (mf_行输入回调) {
		mf_行输入回调(this, m_文档->m_文本块[行号].m_一行, 输入类型);
	}
	//C_文本框::f_插入行(行号);

	f_添加行大小(1);
}

void C_文本编辑框::f_删除行(uint32 行号) {
	if (m_文档->m_文本块.size() > 行号) {
		m_文档->m_文本块.erase(m_文档->m_文本块.begin() + 行号);
	}
	else {
		m_文档->m_文本块.erase(m_文档->m_文本块.begin() + 行号);
	}


	if (m_文档->m_文本块.size() > 10) {
		vec2 size = m_Size;
		size.y -= m_行距 + m_字号;
		f_setSize(size);
	}
}

void C_文本编辑框::f_清除字符() {
	m_光标坐标索引.x = m_选取.开始行列.x;
	m_光标坐标索引.y = m_选取.开始行列.y;
}

void C_文本编辑框::f_添加行大小(uint32 num) {
	float32 行高度 = (m_行距 + m_字号) * m_UIctx->m_DPI;
	vec2 size = m_Size;
	size.y += 行高度 * num;
	f_setSize(size);


	if (m_光标坐标索引.y * 行高度 + m_Pos.y + 行高度 > m_父部件->m_Size.y - S_UI主题::ui_滚动条厚度) {
		size = m_Pos;
		size.y -= 行高度 * num;
		f_setPos(size);
	}
}

void C_文本编辑框::f_减少行大小(uint32 num) {
	float32 行高度 = (m_行距 + m_字号);
	vec2 size = m_Size;
	size.y -= 行高度 * num;
	f_setSize(size);


	if (m_光标坐标索引.y * 行高度 + m_Pos.y + 行高度 > m_父部件->m_Size.y - S_UI主题::ui_滚动条厚度) {
		size = m_Pos;
		size.y += 行高度 * num;
		f_setPos(size);
	}
}

void C_文本编辑框::f_置光标索引() {
	m_光标坐标索引 = f_计算光标索引();

	m_选取.开始行列 = m_光标坐标索引;
	m_选取.结束行列 = m_选取.开始行列;
}

void C_文本编辑框::f_插入文本(const std::vector<std::u16string>& texts) {
	uint32 num = texts.size();
	
	uint32 偏移 = f_删除选择字符();

	if (num > 1) {
		uint32 i = 0;
		if (m_光标坐标索引.x <= m_文档->m_文本块[m_光标坐标索引.y].m_一行.size()) {
			f_拆分行(m_光标坐标索引);


			auto& e = texts.front();
			auto& line = m_文档->m_文本块[m_光标坐标索引.y].m_一行;
			auto& color = m_文档->m_文本块[m_光标坐标索引.y].m_颜色;
			line.insert(line.begin() + 偏移, e.begin(), e.end());

			std::vector<S_RGBA8UI> 新颜色(e.size(), S_UI主题::uic_终端文字);
			color.insert(color.begin() + 偏移, 新颜色.begin(), 新颜色.end());
			++i;
		}

		
		for (; i < num; ++i) {
			auto& e = texts[i];

			S_着色文本块 文本块;
			文本块.m_一行 = texts[i];
			文本块.m_颜色 = std::vector<S_RGBA8UI>(texts[i].size(), S_UI主题::uic_终端文字);

			++m_光标坐标索引.y;
			m_文档->m_文本块.insert(m_文档->m_文本块.begin() + (m_光标坐标索引.y), 文本块);
		}


		if (mf_行输入回调) {
			std::u16string tempStr;
			for(auto& e : texts) tempStr += e;
			mf_行输入回调(this, tempStr, E_字符输入类型::e_常规);
		}
	}
	else {
		auto& e = texts.front();

		auto& line = m_文档->m_文本块[m_光标坐标索引.y].m_一行;
		auto& color = m_文档->m_文本块[m_光标坐标索引.y].m_颜色;
		line.insert(line.begin() + 偏移, e.begin(), e.end());

		std::vector<S_RGBA8UI> 新颜色(e.size(), S_UI主题::uic_终端文字);
		color.insert(color.begin() + 偏移, 新颜色.begin(), 新颜色.end());

		assert(line.size() == color.size());

		m_光标坐标索引.x = 偏移 + e.size();
	}

	
	m_选取.开始行列 = m_光标坐标索引;
	m_选取.结束行列 = m_选取.开始行列;

	f_添加行大小(num);
}

void C_文本编辑框::f_拷贝() {
	std::u16string 切片 = f_取选择文本();

	auto t = f_str_u16_to_u8(切片);
	f_sys_写到剪切板(t);
}

void C_文本编辑框::f_粘贴() {

}

void C_文本编辑框::f_剪切() {
	f_拷贝();
	f_删除选择字符();
}

bool C_文本编辑框::f_拆分行(ivec2 光标) {
	auto 行 = m_文档->m_文本块[光标.y].m_一行;
	光标.x = 行.size();

	std::u16string 文本前半部分 = 行.substr(0, 光标.x);
	std::u16string 文本后半部分;
	if (光标.x < 行.size()) {
		文本后半部分 = 行.substr(光标.x, -1);
	}
	if(文本后半部分.empty() && 文本前半部分.empty()) return false;


	S_着色文本块 新行文本块;
	新行文本块.m_一行 = 文本后半部分;
	新行文本块.m_颜色.insert(新行文本块.m_颜色.end(), m_文档->m_文本块[光标.y].m_颜色.begin() + 光标.x, m_文档->m_文本块[光标.y].m_颜色.end());

	auto& e = m_文档->m_文本块[光标.y];

	e.m_一行 = 文本前半部分;
	e.m_颜色.erase(e.m_颜色.begin() + 光标.x, e.m_颜色.end());

	m_文档->m_文本块.insert(m_文档->m_文本块.begin() + 光标.y + 1, 新行文本块);
	return true;
}

vec2 C_文本编辑框::f_光标绘制坐标() {
	float32 dpi = m_UIctx->m_DPI;

	auto 行文本 = m_文档->m_文本块[m_光标坐标索引.y].m_一行.substr(0, m_光标坐标索引.x);
	float32 行高 = (m_行距 + m_字号) * dpi;

	if (m_光标坐标索引.x <= 0) {
		C_文本框::g光标绘制位置.x = -m_字间距*dpi;
	}
	else {
		C_文本框::g光标绘制位置.x = f_vg_getStringSize(*m_字体, 行文本, m_字号*dpi, m_字间距*dpi);
	}
	C_文本框::g光标绘制位置.x += f_vg_StringDrawOffset(行高);
	C_文本框::g光标绘制位置.y = 行高 * m_光标坐标索引.y;

	return C_文本框::g光标绘制位置;
}

void C_文本编辑框::f_开启输入() {
	m_开启编辑 = true;
	f_get窗口管理()->m_当前文本输入框 = this;
}

int32 C_文本编辑框::f_删除选择字符() {
	ivec2 开始行列;
	ivec2 结束行列;
	uint32 选择行数量 = f_构建正向选择区间(开始行列, 结束行列) + 1;
	

	uint32 偏移 = 开始行列.x;
	uint32 行 = 开始行列.y;

	for (uint32 i = 1; i <= 选择行数量; ++i) {
		auto& lineText = m_文档->m_文本块[行].m_一行;
		auto& lineColor = m_文档->m_文本块[行].m_颜色;

		uint32 删除数量 = 偏移;
		if (i == 选择行数量) {
			删除数量 = 结束行列.x - 偏移;
		}
		else {
			删除数量 = lineText.size() - 偏移;
		}

		if (删除数量) {
			lineText.erase(偏移, 删除数量);
			lineColor.erase(lineColor.begin() + 偏移, lineColor.begin() + (偏移 + 删除数量));
		}

		if (lineText.empty() && 选择行数量 > 1) {
			m_文档->m_文本块.erase(m_文档->m_文本块.begin() + 行);
		}
		else {
			++行;
		}
		偏移 = 0;
	}

	偏移 = 开始行列.x;
	m_选取.结束行列 = 开始行列;
	m_光标坐标索引 = 开始行列;

	return 偏移;
}

void C_文本编辑框::f_包裹区移动(int32 行) {
	
}

ivec2 C_文本编辑框::f_计算光标索引() {
	vec2 鼠标位置 = f_widget_get鼠标局部位置(C_Widget::g_鼠标.gPos, this);
	float32 行高 = (m_字号 + m_行距) * m_UIctx->m_DPI;

	ivec2 光标;
	光标.y = (鼠标位置.y) / 行高;
	光标.y = DEF_Min(光标.y, m_文档->m_文本块.size() - 1);

	光标.x = f_widget_从鼠标取光标索引(this, 鼠标位置, m_对齐方式, m_文档->m_文本块[光标.y].m_一行, 行高);

	return 光标;
}

uint32 C_文本编辑框::f_构建正向选择区间(ivec2& 开始行列, ivec2& 结束行列) {
	if (m_选取.结束行列.y == m_选取.开始行列.y) {
		开始行列.x = min(m_选取.开始行列.x, m_选取.结束行列.x);
		结束行列.x = max(m_选取.开始行列.x, m_选取.结束行列.x);
	}
	else if (m_选取.结束行列.y > m_选取.开始行列.y) {
		开始行列.x = m_选取.开始行列.x;
		结束行列.x = m_选取.结束行列.x;
	}
	else {
		开始行列.x = m_选取.结束行列.x;
		结束行列.x = m_选取.开始行列.x;
	}

	开始行列.y = min(m_选取.开始行列.y, m_选取.结束行列.y);
	结束行列.y = max(m_选取.开始行列.y, m_选取.结束行列.y);

	return 结束行列.y - 开始行列.y;
}

std::u16string C_文本编辑框::f_取选择文本() {
	ivec2 开始行列;
	ivec2 结束行列;
	uint32 选择行数量 = f_构建正向选择区间(开始行列, 结束行列);

	std::u16string text;

	
	if (选择行数量) {
		text += m_文档->m_文本块[开始行列.y].m_一行.substr(开始行列.x) + u'\r';

		for (uint32 i = 1; i < 选择行数量; ++i) {
			text += m_文档->m_文本块[开始行列.y + i].m_一行 + u'\r';
		}

		text += m_文档->m_文本块[结束行列.y].m_一行.substr(0, 结束行列.x);
	}
	else {
		text += m_文档->m_文本块[开始行列.y].m_一行.substr(开始行列.x, 结束行列.x - 开始行列.x);
	}

	return text;
}

C_Widget* f_ui_创建文本编辑框(S_UI渲染环境& ctx) {
	C_文本编辑框* box = new C_文本编辑框(ctx, S_UI主题::ui_默认字体);
	return box;
}

S_文档文本& f_ui_get编辑框文本块(C_Widget* self) {
	C_文本框& box = * dynamic_cast<C_文本框*>(self);
	return *box.m_文档;
}

std::string f_ui_取编辑框文本块(C_Widget* self) {
	
	return std::string();
}

void f_ui_文本编辑框插入行(C_Widget* self, S_着色文本块 文本块, ivec2 位置) {
	C_文本框& box = * dynamic_cast<C_文本框*>(self);

	
	if (文本块.m_一行.size() != 文本块.m_颜色.size()) {
		int32 缺少数量 = 文本块.m_一行.size() - 文本块.m_颜色.size();

		if (缺少数量 >= 0) {
			std::vector<S_RGBA8UI> 颜色(缺少数量, S_UI主题::uic_文字颜色);
			文本块.m_颜色.insert(文本块.m_颜色.end(), 颜色.begin(), 颜色.end());
		}
		else {
			文本块.m_颜色.resize(文本块.m_一行.size());
		}
	}
	
	if (位置.y >= box.m_文档->m_文本块.size() || 位置.y < 0) {
		box.m_文档->m_文本块.push_back(文本块);

		box.m_光标坐标索引.y = box.m_文档->m_文本块.size() - 1;
		box.m_光标坐标索引.x = 文本块.m_一行.size();
	}
	else {
		auto& e = box.m_文档->m_文本块[位置.y];

		e.m_一行.insert(位置.x, 文本块.m_一行);
		e.m_颜色.insert(e.m_颜色.begin() + 位置.x, 文本块.m_颜色.begin(), 文本块.m_颜色.end());

		//box.m_文档->m_文本块.insert(box.m_文档->m_文本块.begin() + 位置.y, 文本块);
		box.m_光标坐标索引.y = 位置.y;
		box.m_光标坐标索引.x = 位置.x + 文本块.m_一行.size();
	}
	
	box.m_选取.开始行列 = box.m_光标坐标索引;
	box.m_选取.结束行列 = box.m_选取.开始行列;
	self->m_更新绘制属性 = true;
}

void f_ui_置入编辑框输入提示文本(C_Widget* self, const std::vector<std::string>& 提示选项) {
	if (self->m_Type == E_WidgetType::t_文本编辑框) {
		C_文本编辑框& box = *dynamic_cast<C_文本编辑框*>(self);

		S_菜单创建参数 item;
		//for (auto it = 提示选项.begin(); it != 提示选项.end(); ++it) {
		for (auto& e : 提示选项) {
			if(e.empty() == false) item.item.push_back({ f_str_string_to_u16(e), u"", u"", 0});
		}
		if (item.item.empty()) {
			f_ui_关闭弹出窗口(box.mui_代码提示菜单);
		}
		else {
			item.mf_菜单项点击 = on_代码提示菜单项;

			f_ui_置菜单项焦点(box.mui_代码提示菜单, 0);

			vec2 pos = box.g光标绘制位置 + box.m_GlobalLoc;
			pos.y += (box.m_字号 + box.m_行距 * 0.5) * self->m_UIctx->m_DPI;
			f_ui_打开动态菜单(box.mui_代码提示菜单, pos, self, item, true, true);
		}
	}
}

void f_ui_关闭编辑框提示菜单(C_Widget* self) {
	
}

std::string f_ui_取编辑框光标行文本(C_Widget* self) {
	C_文本框& box = *dynamic_cast<C_文本框*>(self);
	return f_str_u16_to_u8(box.m_文档->m_文本块[box.m_光标坐标索引.y].m_一行);
}


void f_ui_添加文本包裹绘制(C_文本框* self, int32 开始行, int32 增加行) {
	C_文本编辑框& box = *static_cast<C_文本编辑框*>(self);
	float32 dpi = self->m_UIctx->m_DPI;

	auto it = std::find_if(box.m_代码包裹.begin(), box.m_代码包裹.end(), [&](ivec3& val){ 
		if(val.x == 开始行) {
			float32 w = f_vg_getStringSize(*(box.m_字符->m_字体), box.m_文档->m_文本块[开始行 + val.y - 1].m_一行, box.m_字号 * dpi, box.m_字间距 * dpi);
			w += f_vg_StringDrawOffset(box.m_字号 + box.m_行距) * dpi * 2;
			val.z = max(w, val.z);
			val.y += 增加行;
			return true;  
		}
		else {
			return false;
		}
	});

	if (it == box.m_代码包裹.end()) {
		float32 w = f_vg_getStringSize(*(box.m_字符->m_字体), box.m_文档->m_文本块[开始行].m_一行, box.m_字号 * dpi, box.m_字间距 * dpi);
		w += f_vg_StringDrawOffset(box.m_字号 + box.m_行距) * dpi * 2;

		box.m_代码包裹.push_back({开始行, 增加行, int32(w)});
	}
	
}

std::string f_ui_取编辑框包裹文本(C_文本框* self, int32 开始行) {
	C_文本编辑框& box = *static_cast<C_文本编辑框*>(self);
	std::string code;

	auto it = std::find_if(box.m_代码包裹.begin(), box.m_代码包裹.end(), [&](ivec3& val){ 
		if(val.x == 开始行) {
			return true;  
		}
		else {
			return false;
		}
	});


	if (it != box.m_代码包裹.end()) {
		ivec3& r = *it;

		for (uint32 i = 0; i < r.y; ++i) {
			auto& str = box.m_文档->m_文本块[r.x + i];

			code += f_str_u16_to_u8(str.m_一行) + '\r';
		}

		for (int32 i = r.y; i > 0; ) {
			--i;

			auto& str = box.m_文档->m_文本块[r.x + i];
			if (str.m_一行.empty() || str.m_一行 == u"\r") {
				--r.y;
				break;
			}
		}
	}

	return code;
}








